<!DOCTYPE html>
<html lang="en">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Nami 聊天客户端</title>
    <style>
        * {
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }

        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f9;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }

        .container {
            width: 1000px;
            height: 700px;
            background-color: #fff;
            display: flex;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }

        /* 左侧功能区 */
        .left-panel {
            width: 80px;
            background-color: #f8f9fa;
            border-right: 1px solid #ddd;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 10px;
        }

        .left-panel .avatar {
            width: 50px;
            height: 50px;
            border-radius: 50%;
            margin-bottom: 20px;
        }

        .left-panel .nickname {
            width: 70px; /* 限制宽度 */
            white-space: nowrap; /* 禁止换行 */
            overflow: hidden; /* 超出部分隐藏 */
            text-overflow: ellipsis; /* 超出部分显示省略号 */
            text-align: center; /* 居中显示 */
            font-size: 12px; /* 字体大小 */
            color: #333; /* 字体颜色 */
            cursor: pointer; /* 鼠标悬停时显示手型 */
            margin-top: -15px; /* 与头像的间距 */
        }

        .left-panel .nickname.expanded {
            white-space: normal; /* 允许换行 */
            overflow: visible; /* 显示全部内容 */
            text-overflow: clip; /* 取消省略号 */
        }

        .left-panel .icon {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-color: #007bff;
            color: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            margin-top: 10px; /* 增加上边距 */
            margin-bottom: 10px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .left-panel .icon:hover {
            background-color: #0056b3;
        }

        /* 左侧会话列表 */
        .sidebar {
            width: 300px;
            background-color: #f8f9fa;
            border-right: 1px solid #ddd;
            padding: 10px;
            overflow-y: auto;
        }

        .sidebar h3 {
            margin-bottom: 10px;
            font-size: 16px;
            color: #333;
        }

        .conversation-list {
            list-style: none;
        }

        /* 会话列表项的样式 */
        .conversation-item {
            display: flex;
            align-items: center;
            padding: 10px;
            margin-bottom: 5px;
            background-color: #fff;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s;
            max-width: 100%; /* 限制最大宽度 */
            overflow: hidden; /* 隐藏溢出内容 */
        }

        .conversation-item:hover {
            background-color: #e9ecef;
        }

        .conversation-item.active {
            background-color: #007bff;
            color: #fff;
        }

        .conversation-item .avatar {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            margin-right: 10px;
        }

        .conversation-item .content {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: center;
            min-width: 0; /* 防止内容溢出 */
        }


        .conversation-item .nickname {
            font-size: 14px;
            font-weight: bold;
            margin-bottom: 4px;
            white-space: nowrap; /* 禁止换行 */
            overflow: hidden; /* 隐藏溢出内容 */
            text-overflow: ellipsis; /* 超出部分显示省略号 */
        }

        .conversation-item .latest-message {
            font-size: 12px;
            color: #666;
            white-space: nowrap; /* 禁止换行 */
            overflow: hidden; /* 隐藏溢出内容 */
            text-overflow: ellipsis; /* 超出部分显示省略号 */
        }

        .conversation-item .time {
            font-size: 12px;
            color: #999;
            margin-left: 10px;
        }

        /* 右侧聊天框 */
        .chat-area {
            flex: 1;
            display: flex;
            flex-direction: column;
            padding: 10px;
            overflow: hidden;
        }

        .chat-header {
            padding: 10px;
            border-bottom: 1px solid #ddd;
            font-size: 18px;
            font-weight: bold;
            display: flex;
            align-items: center;
        }

        .chat-header .avatar {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            margin-right: 10px;
        }

        .chat-input {
            display: flex;
            gap: 10px;
            padding: 10px;
        }

        .chat-input textarea {
            flex: 1;
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
            resize: none;
        }

        .chat-input button {
            padding: 8px 16px;
            background-color: #007bff;
            color: #fff;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        .chat-input button:hover {
            background-color: #0056b3;
        }

        .chat-messages {
            flex: 1;
            overflow-y: auto;
            padding: 10px;
            border-bottom: 1px solid #ddd;
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        /* 消息气泡样式 */
        .chat-messages .message {
            display: flex;
            align-items: flex-start; /* 确保头像和气泡对齐 */
            margin-bottom: 10px;
            max-width: 70%; /* 限制消息的最大宽度 */
        }

        /* 自己发送的消息 */
        .chat-messages .message.self {
            margin-left: auto;
            flex-direction: row-reverse;
        }

        /* 别人发送的消息 */
        .chat-messages .message.other {
            margin-right: auto;

        }

        .chat-messages .message.other .message-content {
            align-items: flex-start; /* 确保头像和气泡对齐 */
            max-width: 80%;

        }

        /* 消息气泡 */
        .chat-messages .message .bubble {
            padding: 10px;
            border-radius: 12px;
            background-color: #f1f1f1;
            position: relative;
            max-width: 80%;
            min-width: 50px; /* 设置最小宽度，避免气泡过小 */
            white-space: pre-wrap; /* 允许长文字换行 */
            word-wrap: break-word; /* 长单词换行 */
        }

        /* 自己发送的消息气泡 */
        .chat-messages .message.self .bubble {
            background-color: #007bff;
            color: #fff;
            margin-left: 10px; /* 与头像的间距 */
        }

        /* 自己发送的消息头像 */
        .chat-messages .message.self .avatar {
            margin-left: 10px; /* 调整左边距 */
            margin-right: 0; /* 移除右边距 */
        }

        /* 别人发送的消息气泡 */
        .chat-messages .message.other .bubble {
            background-color: #e9ecef;
            margin-right: 5px;
        }

        /* 消息气泡的三角形 */
        .chat-messages .message .bubble::after {
            content: '';
            position: absolute;
            top: 10px;
            width: 0;
            height: 0;
            border: 6px solid transparent;
        }

        /* 自己发送的消息气泡三角形 */
        .chat-messages .message.self .bubble::after {
            right: -12px;
            border-left-color: #007bff;
        }

        /* 别人发送的消息气泡三角形 */
        .chat-messages .message.other .bubble::after {
            left: -12px;
            border-right-color: #e9ecef;
        }

        /* 头像样式 */
        .chat-messages .message .avatar {
            width: 30px;
            height: 30px;
            border-radius: 50%;
            margin: 0 10px;
            flex-shrink: 0; /* 防止头像被压缩 */
        }


        /* 昵称样式 */
        .chat-messages .message .nickname {
            font-size: 12px;
            color: #666;
            margin-bottom: 4px;
            text-align: left; /* 默认左对齐 */
        }

        /* 自己发送的消息昵称右对齐 */
        .chat-messages .message.self .nickname {
            text-align: right;
        }

        /* 消息内容容器 */
        .chat-messages .message .message-content {
            display: flex;
            flex-direction: column;
            align-items: flex-end; /* 确保内容左对齐 */
        }

    </style>
</head>

<body>
<div class="container">
    <!-- 左侧功能区 -->
    <div class="left-panel">
        <img src="https://via.placeholder.com/50" alt="头像" class="avatar">
        <div class="nickname" id="leftNickname" title="点击查看完整昵称">${my_nick}</div>
        <div class="icon" onclick="alert('创建会话')">+</div>
        <div class="icon" onclick="alert('消息')">💬</div>
        <div class="icon" onclick="alert('通讯录')">📖</div>
    </div>

    <!-- 左侧会话列表 -->
    <div class="sidebar">
        <h3>会话列表</h3>
        <ul class="conversation-list" id="conversationList">
            <!-- 会话项将通过 JavaScript 动态渲染 -->
        </ul>
    </div>

    <!-- 右侧聊天框 -->
    <div class="chat-area">
        <div class="chat-header" id="chatHeader">
            <img src="https://via.placeholder.com/40" alt="头像" class="avatar">
            <span>请选择一个会话</span>
        </div>
        <div class="chat-messages" id="chatMessages">
            <!-- 聊天消息将通过 JavaScript 动态渲染 -->
        </div>
        <div class="chat-input">
            <textarea id="messageInput" placeholder="输入消息..."></textarea>
            <button onclick="sendMessage()">发送</button>
        </div>
    </div>
</div>

<script>
    const API_BASE_URL = 'http://localhost:8080'; // 后端接口地址
    let socket; // WebSocket 连接
    let currentConversation = null; // 当前选中的会话

    const token = localStorage.getItem("token"); // 从 localStorage 获取 token
    const WS_URL = localStorage.getItem("gateUrl"); // 从 localStorage 获取 token

    const userId = localStorage.getItem("userId");

    let my_nick = "昵称";
    let my_avatar = "";

    let currentPage = 1; // 当前页码
    const pageSize = 10; // 每页数据量
    let isLoading = false; // 是否正在加载数据

    var qosQueue = []; // 存储需要确认的消息 ID
    var isQosRunning = false; // 标记是否正在发送批量 QoS

    function sendBatchQos() {
        if (isQosRunning || qosQueue.length === 0) {
            return;
        }
        isQosRunning = true;

        // 按会话类型分组
        let groupedQos = {};
        qosQueue.forEach(item => {
            if (!groupedQos[item.converType]) {
                groupedQos[item.converType] = [];
            }
            groupedQos[item.converType].push(item.msgId);
        });

        // 发送每组 QoS
        Object.keys(groupedQos).forEach(converType => {
            let msgIds = groupedQos[converType];

            let qosData = {
                senderId: userId,
                receiverId: "0",
                msgIds: msgIds,
                converType: converType
            };

            console.log("发送批量 QoS:", qosData);
            socket.send(createCustomMessage(199, 1, 1, 10, JSON.stringify(qosData)));
        });

        // 清空队列
        qosQueue = [];
        isQosRunning = false;
    }

    function getUserInfo() {

        fetch(`${API_BASE_URL}/web/user/info?userId=${userId}`, {
            headers: {
                "clientid": "fdsdfdf2323hfdgk5645",
                "Authorization": `Bearer ${token}`,
                "Content-Type": "application/json",
            },
        })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`请求失败，状态码：${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                if (data.code === 200) {

                    if (data.data.nick != undefined || data.data.nick != null) {
                        my_nick = data.data.nick;
                    }
                    my_avatar = data.data.avatar;
                    console.log("nick=", my_avatar);
                    // 更新左侧头像
                    document.querySelector('.left-panel .avatar').src = my_avatar;
                    const leftNickname = document.getElementById('leftNickname');
                    leftNickname.textContent = my_nick;
                    leftNickname.title = my_nick; // 设置 title 为完整昵称

                } else {
                    console.error("获取用户信息出错：", data.msg);
                }
            })
            .catch(error => {
                console.error("请求出错：", error);
            });
    }

    function checkUserExist() {
        if (userId === null || userId === undefined) {
            console.log("查找用户失败。")
            window.location.href = './login.html';
        }
    }

    // 初始化页面
    window.onload = function () {
        checkUserExist();
        getUserInfo();
        connectWebSocket(); // 自动连接 WebSocket
        fetchConversations(); // 获取第一页会话列表
        setupScrollListener(); // 设置滚动监听
    };

    // 连接 WebSocket
    function connectWebSocket() {
        const wsUrl = WS_URL || "ws://localhost:30000/ws";
        socket = new WebSocket(wsUrl);

        socket.onopen = function () {
            console.log("WebSocket 连接成功");
            socket.binaryType = "arraybuffer";

            logout(`${userId}`, "windows", "test");
            login(`${userId}`, "windows", "test");
            setInterval(sendBatchQos, 1000);
        };

        socket.onmessage = function (event) {
            const receivedObject = parseBinaryDataToObject(event);
            console.log("收到消息:", receivedObject);

            if (receivedObject.cmd === 1001) { // 登录成功
                console.log("开始发送心跳");
                heartBeat();
            }
            if (receivedObject.cmd === 1002) { // pong
                heartBeat();
            }
            if (receivedObject.cmd === 1003) { // 单聊
                let dataStr = JSON.parse(receivedObject.data);
                let message = JSON.parse(dataStr.data);
                console.log("----- ", message);
                // 接收者
                if (userId != message.senderId) {
                    if (qosQueue.some(item => item.msgId === message.id && item.converType === message.conversationType)) {
                        console.log("已接收到.");
                        return;
                    }
                    // qos
                    qosQueue.push({
                        msgId: message.id,
                        converType: message.conversationType
                    });
                    console.log("单聊消息添加到 QoS 队列:", message.id);
                }
                handleReceivedMessage(message);
            }
            if (receivedObject.cmd === 1005) { // 群聊
                let dataStr = JSON.parse(receivedObject.data);
                let message = JSON.parse(dataStr.data);
                console.log("------------------vvvv", message);
                // 接收者
                if (userId != message.senderId) {
                    if (qosQueue.some(item => item.msgId === message.id && item.converType === message.conversationType)) {
                        console.log("已接收到.");
                        return;
                    }
                    // qos
                    qosQueue.push({
                        msgId: message.id,
                        converType: message.conversationType
                    });
                    console.log("群聊消息添加到 QoS 队列:", message.id);
                }

                console.log("messge type ", message.type)
                if (message.type === 203 || message.type === 201 || message.type === 10) {
                    console.log("messge type ", message.type)
                    return
                }

                // 处理消息逻辑
                handleGrpReceivedMessage(message);

            }


        };

        socket.onclose = function () {
            console.log("WebSocket 连接关闭");
        };
    }

    function logout(userId, systemOs, appKey) {
        var cmd = 200;
        var version = 1;
        var serial = 10;
        var encrypt = 1;

        var data = {
            "userId": userId,
            "appKey": appKey,
            "deviceType": 13,
            "currTime": new Date().getTime()
        };
        var jsonData = JSON.stringify(data);
        console.log(jsonData);
        socket.send(createCustomMessage(cmd, version, encrypt, serial, jsonData));
    }

    function login(userId, systemOs, appKey) {
        if (!window.WebSocket) {
            return;
        }
        console.log(userId);
        // 当websocket状态打开
        if (socket.readyState == WebSocket.OPEN) {
            var cmd = 1;
            var version = 1;
            var serial = 10;
            var encrypt = 1;

            var data = {
                "userId": userId,
                "appKey": appKey,
                "systemOs": systemOs,
                "deviceType": 13,
                "token": null,
                "currTime": new Date().getTime()
            };
            var jsonData = JSON.stringify(data);
            console.log(jsonData);
            socket.send(createCustomMessage(cmd, version, encrypt, serial, jsonData));
        } else {
            alert("连接没有开启");
        }
    }

    // 获取会话列表
    function fetchConversations(pageNum = 1) {
        if (isLoading) return; // 如果正在加载数据，直接返回
        isLoading = true; // 标记为正在加载

        const token = localStorage.getItem("token"); // 从 localStorage 获取 token
        if (!token) {
            console.error("未找到 token，请先登录");
            return;
        }

        fetch(`${API_BASE_URL}/web/conver/list?pageNum=${pageNum}&pageSize=${pageSize}`, {
            headers: {
                "clientid": "fdsdfdf2323hfdgk5645",
                "Authorization": `Bearer ${token}`,
                "Content-Type": "application/json",
            },
        })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`请求失败，状态码：${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                if (data.code === 200) {
                    if (pageNum === 1) {
                        // 如果是第一页，直接渲染
                        renderConversationList(data.rows);
                    } else {
                        // 如果是后续页，追加数据
                        appendConversationList(data.rows);
                    }
                    currentPage = pageNum; // 更新当前页码
                } else {
                    console.error("获取会话列表失败：", data.msg);
                }
            })
            .catch(error => {
                console.error("请求出错：", error);
            })
            .finally(() => {
                isLoading = false; // 标记为加载完成
            });
    }

    // 渲染会话列表
    function renderConversationList(conversations) {
        const conversationList = document.getElementById("conversationList");
        conversationList.innerHTML = ""; // 清空列表
        appendConversationList(conversations); // 追加数据
    }

    // 追加会话列表
    function appendConversationList(conversations) {
        const conversationList = document.getElementById("conversationList");

        conversations.forEach(conversation => {
            const li = document.createElement("li");
            li.className = "conversation-item";

            // 头像
            const avatarUrl = conversation.targetUser?.avatarUrl || conversation.group?.groupAvatar || "https://via.placeholder.com/40";
            const avatar = document.createElement("img");
            avatar.src = avatarUrl;
            avatar.className = "avatar";
            li.appendChild(avatar);

            // 内容区域
            const content = document.createElement("div");
            content.className = "content";

            // 昵称
            const nickname = document.createElement("div");
            nickname.className = "nickname";
            nickname.textContent = conversation.targetUser?.nickname || conversation.group?.name || `会话 ${conversation.targetId}`;
            content.appendChild(nickname);

            // 最新消息
            const latestMessage = document.createElement("div");
            latestMessage.className = "latest-message";

            // 提取 payload 中的 text 内容
            let messageText = "暂无消息";
            if (conversation.message?.payload) {
                try {
                    const payload = JSON.parse(conversation.message.payload);
                    messageText = payload.text || "暂无消息";
                } catch (e) {
                    console.error("解析 payload 失败：", e);
                    messageText = conversation.message.payload; // 如果解析失败，直接显示原始内容
                }
            }
            latestMessage.textContent = messageText;
            content.appendChild(latestMessage);

            li.appendChild(content);

            // 时间
            const time = document.createElement("div");
            time.className = "time";
            time.textContent = formatTime(conversation.message?.sendTime);
            li.appendChild(time);

            li.addEventListener("click", () => selectConversation(conversation));
            conversationList.appendChild(li);
        });
    }

    // 格式化时间
    function formatTime(timestamp) {
        if (!timestamp) return "";
        const date = new Date(timestamp);
        return `${date.getHours()}:${String(date.getMinutes()).padStart(2, "0")}`;
    }

    // 监听滚动事件
    function setupScrollListener() {
        const chatMessages = document.getElementById("chatMessages");
        let isThrottled = false;

        chatMessages.addEventListener("scroll", () => {
            if (isThrottled) return;
            isThrottled = true;

            setTimeout(() => {
                const { scrollTop, scrollHeight, clientHeight } = chatMessages;
                const threshold = 100; // 距离顶部 100px 时触发加载

                if (scrollTop < threshold && !isLoading) {
                    fetchHistoryMessages(currentConversation.targetId, currentConversation.converType);
                }

                isThrottled = false;
            }, 200); // 200ms 的防抖时间
        });
    }

    // 选择会话
    function selectConversation(conversation) {
        console.log("切换会话：", conversation);
        currentConversation = conversation;
        lastSeq = 0; // 重置 lastSeq
        const chatHeader = document.getElementById("chatHeader");
        chatHeader.innerHTML = `
        <img src="${conversation.targetUser?.avatarUrl || conversation.group?.groupAvatar || "https://via.placeholder.com/40"}" alt="头像" class="avatar">
        <span>${conversation.targetUser?.nickname || conversation.group?.name || `会话 ${conversation.targetId}`}</span>
    `;

        // 清空聊天内容
        const chatMessages = document.getElementById("chatMessages");
        chatMessages.innerHTML = "";

        // 获取历史消息
        fetchHistoryMessages(conversation.targetId, conversation.converType);
    }

    let lastSeq = 0; // 用于记录上一次请求的最后一条消息的 seq
    function fetchHistoryMessages(targetId, converType, pageNum = 1) {
        const token = localStorage.getItem("token"); // 从 localStorage 获取 token
        if (!token) {
            console.error("未找到 token，请先登录");
            return;
        }

        const url = `${API_BASE_URL}/web/msg/qryHisMsgs?userId=${userId}&targetId=${targetId}&pageSize=20&converType=${converType}&lastSeq=${lastSeq}`;

        // 获取当前滚动位置
        const chatMessages = document.getElementById("chatMessages");
        const scrollTopBefore = chatMessages.scrollTop;
        const scrollHeightBefore = chatMessages.scrollHeight;

        fetch(url, {
            headers: {
                "clientid": "fdsdfdf2323hfdgk5645",
                "Authorization": `Bearer ${token}`,
                "Content-Type": "application/json",
            },
        })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`请求失败，状态码：${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                console.log("后端返回的数据：", data);
                if (data.code === 200) {
                    if (data.data.messages ===undefined || data.data.messages === null
                        || data.data.messages.length === 0) {
                        console.log("没有更多历史消息");
                        return;
                    }
                    renderMessages(data.data.messages);

                    // 更新 lastSeq 为返回的最后一条消息的 seq
                    if (data.data.messages.length > 0) {
                        lastSeq = data.data.messages[data.data.messages.length - 1].seq;
                    }

                    // 保持滚动位置不变
                    const scrollHeightAfter = chatMessages.scrollHeight;
                    chatMessages.scrollTop = scrollTopBefore + (scrollHeightAfter - scrollHeightBefore);
                } else {
                    console.error("获取历史消息失败：", data.msg || "messages 不是数组");
                }
            })
            .catch(error => {
                console.error("请求出错：", error);
            });
    }

    // 发送消息
    function sendMessage() {
        const messageInput = document.getElementById("messageInput");
        const message = messageInput.value.trim();

        if (message && currentConversation) {
            let cmd = 3;
            let converType = 'c2c';
            if (currentConversation.converType === 2) {
                converType = 'c2g';
                cmd = 5;
            }
            const messageData = {
                senderId: `${userId}`,
                receiverId: currentConversation.targetId,
                payload: JSON.stringify({text: message}),
                payloadType: 'text',
                conversationType: converType,
                type: 1,
                flow: 'up',
                clientMsgId: uuid(),
                time: new Date().getTime()
            };
            console.log("发送消息：", messageData);
            socket.send(createCustomMessage(cmd, 1, 1, 10, JSON.stringify(messageData)));

            // 手动将消息添加到聊天框中
            const chatMessages = document.getElementById("chatMessages");
            const div = document.createElement("div");
            div.className = "message self"; // 自己发送的消息

            // 头像
            const avatarImg = document.createElement("img");
            avatarImg.src = my_avatar;
            avatarImg.className = "avatar";
            div.appendChild(avatarImg);

            // 消息内容
            const bubble = document.createElement("div");
            bubble.className = "bubble";
            bubble.textContent = message;
            div.appendChild(bubble);

            chatMessages.appendChild(div);

            // 滚动到底部
            chatMessages.scrollTop = chatMessages.scrollHeight;

            messageInput.value = ""; // 清空输入框
        }
    }

    // 渲染聊天消息
    function renderMessages(messages) {
        const chatMessages = document.getElementById("chatMessages");

        // 如果 lastSeq 为 0，表示是第一次加载，清空消息
        if (lastSeq === 0) {
            chatMessages.innerHTML = "";
        }

        messages.forEach(message => {
            const isSelf = message.senderId === `${userId}`;
            const div = document.createElement("div");
            div.className = `message ${isSelf ? "self" : "other"}`;

            // 头像
            const avatar = document.createElement("img");
            if (isSelf) {
                avatar.src = my_avatar; // 自己的头像
            } else {
                if (currentConversation.converType === 1) { // 单聊
                    avatar.src = currentConversation.targetUser?.avatarUrl || "https://via.placeholder.com/40";
                } else if (currentConversation.converType === 2) { // 群聊
                    avatar.src = message.senderInfo.avatar || "https://via.placeholder.com/40";
                }
            }
            avatar.className = "avatar";
            div.appendChild(avatar);

            // 消息内容容器
            const messageContent = document.createElement("div");
            messageContent.className = "message-content";

            // 如果是群聊且不是自己发送的消息，显示昵称
            if (currentConversation.converType === 2 && !isSelf) {
                const nickname = document.createElement("div");
                nickname.className = "nickname";
                nickname.textContent = message.senderInfo.nick || "未知用户";
                messageContent.appendChild(nickname);
            }

            // 消息气泡
            const bubble = document.createElement("div");
            bubble.className = "bubble";

            // 提取 payload 中的 text 内容
            let messageText = message.payload;
            if (message.payload) {
                try {
                    const payload = JSON.parse(message.payload);
                    messageText = payload.text || message.payload;
                } catch (e) {
                    console.error("解析 payload 失败：", e);
                    messageText = message.payload; // 如果解析失败，直接显示原始内容
                }
            }
            bubble.textContent = messageText;
            messageContent.appendChild(bubble);

            div.appendChild(messageContent);

            // 将新消息插入到现有消息的上方
            chatMessages.insertBefore(div, chatMessages.firstChild);
        });

        // 如果 lastSeq 为 0，表示是第一次加载，滚动到底部
        if (lastSeq === 0) {
            chatMessages.scrollTop = chatMessages.scrollHeight;
        }
    }

    // 处理收到的消息
    function handleReceivedMessage(message) {

        const chatMessages = document.getElementById("chatMessages");
        const isSelf = message.senderId === `${userId}`;
        const div = document.createElement("div");
        div.className = `message ${isSelf ? "self" : "other"}`;

        // 头像
        const avatarImg = document.createElement("img");
        avatarImg.src = isSelf ? my_avatar : (currentConversation.targetUser?.avatarUrl || currentConversation.group?.groupAvatar || "https://via.placeholder.com/40");
        avatarImg.className = "avatar";
        div.appendChild(avatarImg);

        // 消息内容容器
        const messageContent = document.createElement("div");
        messageContent.className = "message-content";

        // 如果不是自己发送的消息，显示昵称
        if (!isSelf) {
            const nickname = document.createElement("div");
            nickname.className = "nickname";
            nickname.textContent = message.senderInfo?.nick || "未知用户";
            messageContent.appendChild(nickname);
        }

        // 消息气泡
        const bubble = document.createElement("div");
        bubble.className = "bubble";

        // 提取 payload 中的 text 内容
        let messageText = message.payload;
        if (message.payload) {
            try {
                const payload = JSON.parse(message.payload);
                messageText = payload.text || message.payload;
            } catch (e) {
                console.error("解析 payload 失败：", e);
                messageText = message.payload; // 如果解析失败，直接显示原始内容
            }
        }
        bubble.textContent = messageText;
        messageContent.appendChild(bubble);

        div.appendChild(messageContent);

        chatMessages.appendChild(div);

        // 滚动到底部
        chatMessages.scrollTop = chatMessages.scrollHeight;

    }

    function handleGrpReceivedMessage(message) {

        const chatMessages = document.getElementById("chatMessages");
        const isSelf = message.senderId === `${userId}`;
        const div = document.createElement("div");
        div.className = `message ${isSelf ? "self" : "other"}`;

        // 头像
        const avatarImg = document.createElement("img");
        avatarImg.src = isSelf ? my_avatar : (message.senderInfo?.avatar || "https://via.placeholder.com/40");
        avatarImg.className = "avatar";
        div.appendChild(avatarImg);

        // 消息内容容器
        const messageContent = document.createElement("div");
        messageContent.className = "message-content";

        // 如果是群聊且不是自己发送的消息，显示昵称
        if (!isSelf) {
            const nickname = document.createElement("div");
            nickname.className = "nickname";
            nickname.textContent = message.senderInfo?.nick || "未知用户";
            messageContent.appendChild(nickname);
        }

        // 消息气泡
        const bubble = document.createElement("div");
        bubble.className = "bubble";

        // 提取 payload 中的 text 内容
        let messageText = message.payload;
        if (message.payload) {
            try {
                const payload = JSON.parse(message.payload);
                messageText = payload.text || message.payload;
            } catch (e) {
                console.error("解析 payload 失败：", e);
                messageText = message.payload; // 如果解析失败，直接显示原始内容
            }
        }
        bubble.textContent = messageText;
        messageContent.appendChild(bubble);

        div.appendChild(messageContent);

        chatMessages.appendChild(div);

        // 滚动到底部
        chatMessages.scrollTop = chatMessages.scrollHeight;

    }

    // 其他函数（createCustomMessage、parseBinaryDataToObject 等）保持不变
    // 定义 createCustomMessage 函数
    function createCustomMessage(cmd, version, encrypt, serial, dataStr) {
        // 魔术值固定为8
        const magic = 8;

        // 假设所有字节数据都在0-255之间

        // 创建魔术值视图
        const magicView = new DataView(new ArrayBuffer(1));
        magicView.setUint8(0, magic);

        // 创建cmd视图，现在它是4个字节
        const cmdView = new DataView(new ArrayBuffer(4));
        cmdView.setUint32(0, cmd, false); // 注意endianness（这里是大端序）

        const versionView = new DataView(new ArrayBuffer(1));
        versionView.setUint8(0, version);

        const encryptView = new DataView(new ArrayBuffer(1));
        encryptView.setUint8(0, encrypt);

        const serialView = new DataView(new ArrayBuffer(1));
        serialView.setUint8(0, serial);

        // 将字符串转换为UTF-8编码的ArrayBuffer
        let encoder = new TextEncoder();
        let dataView = encoder.encode(dataStr);

        // 计算并添加4字节的长度字段
        let dataLength = dataView.byteLength;
        console.log("datalenght=", dataLength);
        const lengthView = new DataView(new ArrayBuffer(4));
        lengthView.setUint32(0, dataLength, false); // 注意endianness（这里是大端序）

        // 合并所有的ArrayBuffer
        let totalLength = 1 + 4 + 1 + 1 + 1 + 4 + dataView.byteLength;
        let combinedBuffer = new ArrayBuffer(totalLength);
        let combinedView = new DataView(combinedBuffer);

        // 复制每个部分到combinedBuffer中
        let offset = 0;

        // 首先复制魔术值
        combinedView.setUint8(offset++, magicView.getUint8(0));

        // 然后复制cmd字段
        for (let i = 0; i < 4; i++) {
            combinedView.setUint8(offset++, cmdView.getUint8(i));
        }

        combinedView.setUint8(offset++, versionView.getUint8(0));
        combinedView.setUint8(offset++, encryptView.getUint8(0));
        combinedView.setUint8(offset++, serialView.getUint8(0));

        // 复制长度字段
        for (let i = 0; i < 4; i++) {
            combinedView.setUint8(offset++, lengthView.getUint8(i));
        }

        // 最后复制数据
        for (let i = 0; i < dataView.byteLength; i++) {
            combinedView.setUint8(offset++, dataView[i]);
        }

        return combinedBuffer;
    }

    // 定义 parseBinaryDataToObject 函数
    function parseBinaryDataToObject(event) {
        let combinedView = new DataView(event.data);
        console.log('[receive] total packet length:', combinedView.byteLength);
        // 读取字节数据
        let magic = combinedView.getUint8(0);
        let cmd = combinedView.getUint32(1);

        let version = combinedView.getUint8(5);

        let encrypt = combinedView.getUint8(6);

        let serial = combinedView.getUint8(7);

        let length = combinedView.getUint32(8);

        // 获取字符串数据的位置和长度
        let dataOffset = 12;

        let dataLength = combinedView.byteLength - dataOffset;

        // 创建一个只包含字符串部分的新ArrayBuffer
        let dataBuffer = event.data.slice(dataOffset, dataOffset + dataLength);

        // 解码为字符串
        let decoder = new TextDecoder();
        let dataStr = decoder.decode(dataBuffer);

        return {
            cmd,
            version,
            encrypt,
            serial,
            length,
            data: dataStr
        };
    }

    // 定义 uuid 函数
    function uuid() {
        var s = [];
        var hexDigits = "0123456789abcdef";
        for (var i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23] = "-";

        var uuid = s.join("");
        return uuid;
    }

    // 定义 heartBeat 函数
    function heartBeat() {
        setTimeout(() => {
            console.log("ping...");
            var messageData = {
                // "sendId": ""
            };
            var jsonData = JSON.stringify(messageData);
            // console.log(jsonData)
            socket.send(createCustomMessage(2, 1, 1, 10, jsonData));
        }, 30000);
    }

</script>
</body>

</html>
